﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Windows;
using GBL.Repository.CoatOfArms;
using GBL.Repository.Resources;
using GBlason.Common.Attribute;
using GBlason.Culture;
using GBlason.ViewModel.Contract;
using GBlasonLogic.Tools;

namespace GBlason.ViewModel.CoatOfArm
{
    public class DivisionViewModel : CoatOfArmComponent, IDivisible, ILineCustomizable, IFillable, IDeletionConstrained
    {
        /// <summary>
        /// Gets the name of the component. Use a special resource call depending on the type of division
        /// </summary>
        /// <value>
        /// Get the name of the component or String.Empty if no resources are found for the given type.
        /// </value>
        public override String ComponentName
        {
            get
            {
                var rm = new System.Resources.ResourceManager(typeof(BlasonVocabulary));
                return String.Format(CultureInfo.CurrentCulture,
                    base.ComponentName,
                    rm.GetString(DivisionType.ToString(), CultureInfo.CurrentCulture));
            }
        }

        #region properties

        /// <summary>
        /// Gets or sets the type of the division.
        /// </summary>
        /// <value>
        /// The type of the division.
        /// </value>
        public DivisionType DivisionType { get; set; }

        /// <summary>
        /// Gets or sets the division position.
        /// The division are mostly several subparts of a parent, in this case we need to know for each of them where they are supposed to be
        /// </summary>
        /// <value>
        /// The division position.
        /// </value>
        public Points DivisionPosition { get; set; }

        private Division _originObject;

        /// <summary>
        /// Gets or sets the origin object (from the repository).
        /// The repository objects are used for saving and loading, they are not intended to store the data at run time or in edition mode.
        /// They are rewritten in saves scenarii (auto or manual)
        /// </summary>
        /// <value>
        /// The origin object.
        /// </value>
        public override object OriginObject
        {
            get { return _originObject ?? (_originObject = new Division()); }
            set
            {
                if (value != _originObject)
                    return;
                var div = value as Division;
                _originObject = div;
                OnPropertyChanged("OriginObject");
            }
        }

        #endregion

        #region IShapable

        private String _geometry;

        /// <summary>
        /// Gets or sets the geometry.
        /// </summary>
        /// <value>
        /// The geometry.
        /// </value>
        public override String Geometry
        {
            get { return _geometry; }
            set
            {
                if (value == _geometry) return;
                _geometry = value;
                OnPropertyChanged("Geometry");
            }
        }

        /// <summary>
        /// Updates the shape from the parent's Shape using the same rule that when created.
        /// </summary>
        public override void UpdateShapeFromParent()
        {
            //todo throw an exception when the parent is not divisible, error !!
            var iDivisibleParent = Parent as IDivisible;
            if (iDivisibleParent == null)
                return;
            Geometry = DivisionManager.GetPathFromConstraints(iDivisibleParent.GetDivisionsConstraints(), GetDivisionsConstraints());
            foreach (var child in Children)
                child.UpdateShapeFromParent();
        }

        #endregion //IShapable

        #region IDivisible

        public void AddDivision(DivisionViewModel division)
        {
            throw new NotImplementedException();
        }

        public Visibility DivisibleVisibility
        {
            get { return Visibility.Visible; }
        }

        public ConstraintDivisionSet GetDivisionsConstraints()
        {
            return new ConstraintDivisionSet
            {
                CurrentGeometry = Geometry,
                Type = typeof(DivisionViewModel),
                TypeOfDivision = DivisionType,
                DivisionPosition = DivisionPosition
            };
        }

        public void RemoveDivision(DivisionViewModel component)
        {
            if (Children.Any(child => child == component))
                Children.Remove(component);
        }

        #endregion

        #region ILineCustomizable

        public object VariationOfLine
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }

        #endregion

        #region IFillable

        private TinctureViewModel _colorFill = TinctureViewModel.DefaultTincture;

        [CoaProperty("PropertyColorFill")]
        public TinctureViewModel ColorFill
        {
            get { return _colorFill; }
            set
            {
                if (_colorFill == value) return;
                _colorFill = value;
                OnPropertyChanged("ColorFill");
            }
        }

        #endregion

        #region IDeletionConstrained

        private IList<CoatOfArmComponent> _constraints;

        public IList<CoatOfArmComponent> Constraints
        {
            get { return _constraints ?? (_constraints = new ObservableCollection<CoatOfArmComponent>()); }
            set
            {
                if (_constraints == value) return;
                _constraints = value;
                OnPropertyChanged("Constraints");
            }
        }

        #endregion

    }
}
